﻿#region

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Web;
using System.Xml.Serialization;

#endregion

namespace Store
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            const string src = @"d:\docs\Books\";
            const string dest = @"c:\temp\store\";

            StoreData storeSrc = Read(src);
            StoreData storeDest = Read(dest);


            SerializeStore(storeSrc);
            SyncStore(storeSrc, dest);

            Console.ReadLine();
        }

        private static void Ceva(bool @bool)
        {
            
        }

        private static void SyncStore(StoreData store, string dest)
        {
            foreach (StoreFile storeFile in store.Collection)
            {
                var absoluteSource = new Uri(new Uri(store.Root, UriKind.Absolute),
                                             new Uri(storeFile.FilePath, UriKind.Relative));
                var absoluteDest = new Uri(new Uri(dest, UriKind.Absolute),
                                           new Uri(storeFile.FilePath, UriKind.Relative));

                string sourcePath = HttpUtility.UrlDecode(absoluteSource.LocalPath);
                string destPath = HttpUtility.UrlDecode(absoluteDest.LocalPath);

                Console.WriteLine(sourcePath);
                Console.WriteLine(destPath);

                try
                {
                    CheckReadAccess(sourcePath);
                    CheckWriteAccess(destPath);

                    Directory.CreateDirectory(GetDirectoryPart(destPath));
                    File.Copy(HttpUtility.UrlDecode(absoluteSource.LocalPath),
                              HttpUtility.UrlDecode(absoluteDest.LocalPath), true);
                }
                catch (SecurityException ex)
                {
                    Console.WriteLine(ex.ToString());
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }

        private static string GetDirectoryPart(string path)
        {
            string[] tokens = path.Split(new[] { "\\" }, StringSplitOptions.None);
            var builder = new StringBuilder();

            for (int i = 0; i < tokens.Length - 1; i++)
            {
                builder.Append(tokens[i] + @"\");
            }

            return builder.ToString();
        }

        private static void CheckReadAccess(string source)
        {
            var fileIoPermission = new FileIOPermission(FileIOPermissionAccess.Read, source);
            fileIoPermission.Demand();
        }

        private static void CheckWriteAccess(string source)
        {
            var fileIoPermission = new FileIOPermission(FileIOPermissionAccess.Write, source);
            fileIoPermission.Demand();
        }

        private static StoreData Read(string src)
        {
            // init's
            var uriSrc = new Uri(src);

            // init store
            var store = new StoreData();
            store.Root = src;
            store.Collection = new StoreCollection();

            // read directories list
            List<string> directories = Directory.EnumerateDirectories(src, "", SearchOption.AllDirectories).ToList();
            directories.Add(src);

            // start enumerate
            int filesCounter = 0;
            foreach (string dir in directories)
            {
                IEnumerable<string> files = Directory.EnumerateFiles(dir, "*.*", SearchOption.AllDirectories);

                foreach (string file in files)
                {
                    // build relative path to store root
                    var uri = new Uri(file);
                    Uri relative = uriSrc.MakeRelativeUri(uri);

                    // add file to store
                    store.Collection.Add(
                        new StoreFile
                            {
                                Id = filesCounter,
                                FilePath = relative.ToString(),
                                AddedDate = DateTime.Now
                            });

                    // increment files counter
                    filesCounter++;
                }
            }

            // final assign
            store.FilesCount = filesCounter;

            return store;
        }

        private static void SerializeStore(StoreData store)
        {
            var serializer = new XmlSerializer(typeof(StoreData));
            using (var writer = new StreamWriter("store.xml"))
            {
                serializer.Serialize(writer, store);
            }
        }

        /*
                private static StoreData DeserializeStore()
                {
                    var deserializer = new XmlSerializer(typeof (StoreData));
                    using (var reader = new StreamReader("store.xml"))
                    {
                        return (StoreData) deserializer.Deserialize(reader);
                    }
                }
        */
    }
}